from fastapi.security import  HTTPBearer
from fastapi.exceptions import HTTPException
from jose import JWTError, jwt
from passlib.context import CryptContext
from typing import Union
from datetime import datetime, timedelta
from fastapi import status
import pytz

from core.Config import settings
from database.mysql import engine

SECRET_KEY = settings.JWT_SECRET_KEY
SECRET_REFRESH_KEY = settings.JWT_SECRET_REFRESH_KEY
ALGORITHM = settings.JWT_ALGORITHM
ACCESS_TOKEN_EXPIRE_MINUTES = settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
bearer = HTTPBearer()


def get_password_hash(password: str) -> str:
    """
    加密明文
    :param password: 明文密码
    :return:
    """
    return pwd_context.hash(password)


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """
    验证明文密码 vs hash密码
    :param plain_password: 明文密码
    :param hashed_password: hash密码
    :return:
    """
    return pwd_context.verify(plain_password, hashed_password)

def generate_token(username: str, expire_time: Union[timedelta, None] = None):
    """生成token"""
    shanghai_tz  = pytz.timezone('Asia/Shanghai')
    to_encode = {"sub": username}.copy()
    refresh_encode = {"sub": username}.copy()
    if expire_time:
        expire = datetime.now(shanghai_tz) + timedelta(minutes=expire_time)
        refresh_expire = datetime.now(shanghai_tz) + timedelta(minutes=expire_time * 2)
    else:
        expire =datetime.now(shanghai_tz) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
        refresh_expire = datetime.now(shanghai_tz) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES * 2)

    to_encode.update(dict(exp=expire))
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

    refresh_encode.update(dict(exp=refresh_expire))
    refresh_encoded_jwt = jwt.encode(refresh_encode, SECRET_REFRESH_KEY, algorithm=ALGORITHM)
    # expire 转表为秒级时间戳
    str_expire_local = expire.strftime("%Y-%m-%d %H:%M:%S")
    return {'accessToken': encoded_jwt, 'refreshToken': refresh_encoded_jwt, 'expires': str_expire_local}

async def refresh_Token(refreshToken:str):
    """刷新用户token"""
    token = refreshToken
    # 获取到刷新token，验证是否正确，如果正确，重新生成token返回给客户端
    # 检测token那个地方应该使用redis来验证
    # 用户的登录生成token的时候，可以吧用户的信息，直接存储在redis里面
    # 如果用户更新自己的信息，就吧redis里面的信息也更新了
    try:
        payload = jwt.decode(token, SECRET_REFRESH_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is not None:
            return generate_token(username)
        else:
            raise HTTPException(detail="token刷新失败", status_code=status.HTTP_401_UNAUTHORIZED)
    except JWTError:
        raise HTTPException(detail="token刷新失败", status_code=status.HTTP_401_UNAUTHORIZED)

